<?php
namespace app\serverfund\logic;

use \app\manage\logic\BaseLogic;
use \think\Db;
/**
 * @author:      李颖
 * @DateTime:    2017-12-21 14:23:18
 * @Description: 杉奇无卡支付 支付宝支付
 */
class SqBankCard extends BaseLogic
{	
	protected $config = 'db_config_fund';
    protected $name = 'pay_log';
	private $agentCode = "372155";//机构号
    private $intMhtCode = "037290058120162";//内部商户号
    private $secret = "5F99C90453545B47E050007F0100A09C";  //秘钥
    private $backEndUrl = "http://newthink.thinklev.com/index.php/manage/index/sqReceivePayNotify";
    private $payQueryUrl = "http://211.152.37.242:8091/posnc-api/api/ncOrder/create";
    private $queryOrderUrl = "http://211.152.37.242:8091/posnc-api/api/order/query";

    function _initialize(){
        header('Content-Type:text/html; charset=utf-8');
	}

    //根据参数获取支付宝二维码图片
    public function sqPayOrder($data): array 
    {
	    $sub['agentCode'] = $this->agentCode;  //机构号
        $sub['intMhtCode'] = $this->intMhtCode;  //内部商户号
        $sub['payType'] = "NC01";  //支付类型,无卡支付
        $sub['goodsName'] = base64_encode($data['goods_name']);  //商品名称(base64编码)
        $sub['merchOrderNo'] = $data['merch_order_no'];  //商户订单号
        $sub['amount'] = $data['amount'];  //交易金额（单位：分）
        $sub['phoneNo'] = $data['phone_no'];  //银行预留手机号
        $sub['customerName'] = base64_encode($data['customer_name']);  //持卡人姓名(base64编码)
        $sub['cerdType'] = "01";  //证件类型
        $sub['cerdId'] = $data['cerd_id'];  //证件号
        $sub['cardNo'] = $data['card_no'];  //银行卡号
        $sub['cvn2'] = $data['cvn2'];  //CVN2
        $sub['validDate'] = $data['valid_date']; //卡有效期（格式：yyMM）
        $sub['backEndUrl'] = base64_encode($this->backEndUrl);  //通知URL（base64加密）
        $sub['createTime'] = date('YmdHis',time());  //请求时间（yyyyMMddHHmmss）
        $sub['sign'] = $this->setsign($sub);
        $url = $this->payQueryUrl;
        return $this->_curlSendData($sub, $url);
    }

    //杉奇无卡支付查询订单
    public function getOrderInfo($data): array 
    {
    	$sub['v'] = "1.6";
    	$sub['agentCode'] = $this->agentCode;  //机构号
    	$sub['merchantNo'] = $this->intMhtCode;  //机构号
    	$sub['createTime'] = date('YmdHis',time());  //请求时间（yyyyMMddHHmmss）
    	$sub['merchantOrderId'] = $data['merchant_order_id'];  //创建订单时的商户订单号
    	$sub['payType'] = "NC01";  //支付类型,无卡支付

    	$sub['sign'] = $this->setsign($sub);
        $url = $this->queryOrderUrl;
        
        return $this->_curlSendData($sub, $url);
    } 

    //签名方式
    private function setsign($data){
	    $secret = $this->secret;  //秘钥
        ksort($data); //升序排列
        $str="";
        foreach ($data as $k=>$v){
            $str.=$k.$v;
        } //键值拼接
        $str=strtoupper(md5($secret.$str.$secret)); //MD5加密并转化为大写
        return $str;
    }

    //发送请求
    private function _curlSendData($postData, $url): array 
    {
        $o = "";
        foreach ( $postData as $k => $v )
        {
            $o.="$k=".urlencode($v)."&";
        }
        $postData = substr($o, 0, -1);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        $output = curl_exec($ch);
        curl_close($ch);
        $res = json_decode($output, true);
        return auto_return($res, $res['respMsg']);
    }

    /*接收异步回调通知 $context形式："respCode=00&settleDate=20171227&cardType=1&payTime=20171227145013&amount=1&acceptTime=20171227145013&payStatus=3&payType=NC01&respMsg=%E6%88%90%E5%8A%9F&res1=40C6B14CD39B7ACEE050007F01003D60&merchantNo=037290058120162&acceptOrderId=23b3463f93654d9ebb9c30709f9988f6&merchantOrderId=374"*/
    public function sqReceivePayNotify($context) 
    {
        //在这里进行将字符串形式转换为数组格式
        $contextArray = $this->_stringToArray($context);  //异步通知返回的结果(数组类型)
        $addLog['xml'] = $contextArray;
        $addLog['out_trade_no'] = $contextArray['merchantOrderId'];
        $addLog['remark'] = $contextArray['res1'];

        $callBackLogic = logic('app\serverfund\logic\CallbackLog');
        //调用的重复检查  +1
        $payLogModel = $this->model('\app\serverfund\model\PayLog');
        $findPayLogWhere['id'] = $contextArray['merchantOrderId'];
        $payLogInfo = $payLogModel->where($findPayLogWhere)->find();
        $maxId = $payLogModel->max('id');
        if(!$payLogInfo){
            $addLog['remark'] = '未找到相应的支付记录' . $payLogModel->getLastSql() . '最大id:' . $maxId;
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'FALSE';
        }
        //这里进行检验以下传来的一些参数是否正确  抵签名验证 
        $checkParam = $this->_checkParam($contextArray, $payLogInfo['return_param']);
        if($checkParam['status'] != SUCCESS_STATUS){
            $ip = request()->ip();
            $addLog['remark'] = $checkParam['msg'] . '一级警告！有人试图模仿支付异步通知！ip地址为' . $ip;
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'SUCCESS';
        }
        
        if($payLogInfo['callback_count'] > 0){
            $addLog['remark'] = '错误：重复调用异步通知回调方法';
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            $payLogModel->where($findPayLogWhere)->setInc('callback_count');
            return 'SUCCESS';
        }
        $payLogModel->where($findPayLogWhere)->setInc('callback_count');
        
        //调用接口查询到的订单信息
        $queryOrderRes = $this->getOrderInfo(['merchant_order_id'=>$contextArray['merchantOrderId']]);//查询订单是否支付  查询远程订单
        if($queryOrderRes['status'] != SUCCESS_STATUS){
            $addLog['remark'] = '查询订单错误：' . $queryOrderRes['msg'];
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'SUCCESS';
        }
        if($queryOrderRes['res']['respData']['orderStatus'] != 1 || $queryOrderRes['res']['respData']['payStatus'] != 3 || $contextArray['payStatus'] != 3){
            $addLog['remark'] = '错误：支付失败!' . $queryOrderRes['msg'];
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'SUCCESS';
        }
        //以下说明  支付真正的已成功
        $trueArr = $queryOrderRes['res'];  //异步通知的订单支付信息
        $merchantOrderId = $trueArr['respData']['merchantOrderId'];

        //检查一下是否已执行过
        $checkWhere['id'] = $merchantOrderId;
        $checkWhere['status'] = 1;
        $checkInfo = $payLogModel->where($checkWhere)->find();
        if($checkInfo){
            $addLog['remark'] = '错误：已执行过该操作，不可重复执行';
            $addLog['status'] = 2;  //支付成功，充值失败
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'SUCCESS';
        }

        //1、检查支付记录
        $_getLogWhere['id'] = $merchantOrderId;
        $payLogInfo = $payLogModel->where($_getLogWhere)->find();
        if(!$payLogInfo){ 
            $this->_callRechargeFailure($trueArr, $_getLogWhere, '未找到相应的支付记录');
            return 'SUCCESS';
        }
        //$savePayLog['return_param'] = $contextArray;
        $this->db()->startTrans();
        try{
            //2、执行系统充值方法
            $rechargeData['user_id'] = $payLogInfo['user_id'];
            $rechargeData['app_id'] = $payLogInfo['app_id'];
            $rechargeData['update_ip'] = request()->ip();
            $rechargeData['user_info'] = '{}';
            $rechargeData['opposite_info'] = '{}';

            if($payLogInfo['recharge_type'] == 'cash'){
                $rechargeData['money'] = $payLogInfo['money'];
                $rechargeRes = logic('app\serverfund\logic\FundAccount')->prepaid($rechargeData);
            }elseif($payLogInfo['recharge_type'] == 'currency'){
                $rechargeData['currency'] = $payLogInfo['receive_param']['recharge_currency'];
                $rechargeRes = logic('app\serverfund\logic\CurrencyAccount')->prepaid($rechargeData);
            }else{
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '该条记录充值类型错误');
                return 'SUCCESS';
            }
            if($rechargeRes['status'] != SUCCESS_STATUS){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '系统充值失败');
                return 'SUCCESS';
            }
            //3、更新pay_log记录表 
            $savePayLog['option_log_id'] = $rechargeRes['res']['autoRes'];
            $savePayLog['status'] = 1;
            $savePayLog['result_status'] = 1;
            $savePayLogRes = $payLogModel->save($savePayLog, $_getLogWhere);
            if(!$savePayLogRes){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '更新支付记录表失败');
                return 'SUCCESS';
            }
            //添加回调记录
            $addLog['remark'] = '充值成功';
            $addLog['status'] = 1;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            if(!$addCallbackLog){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '添加回调记录失败');
                return 'SUCCESS';
            }
            // 提交事务
            $this->db()->commit();
            return 'SUCCESS';

        } catch (\Exception $e) {// 回滚事务
            $this->db()->rollback();
            $saveErroPayLog['status'] = 1;
            $saveErroPayLog['result_status'] = 2;
            $saveErroPayLogRes = $payLogModel->save($saveErroPayLog, $_getLogWhere);
            //添加记录
            $addLog['remark'] = '支付成功，充值失败！错误原因：' . $e->getMessage();
            $addLog['status'] = 2;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'SUCCESS';
        }
    }

    private function _checkParam($param, $dbInfoData): array 
    {
        if($param['res1'] != $dbInfoData['res1'] || $param['amount'] != $dbInfoData['amount']){
            return verify_err(null, '参数错误:res1或amount');
        }
        if($param['payTime'] != $dbInfoData['payTime'] || $param['payType'] != $dbInfoData['payType']){
            return verify_err(null, '参数错误:payTime或payType');
        }
        if($param['cardType'] != $dbInfoData['cardType'] || $param['merchantNo'] != $dbInfoData['merchantNo']){
            return verify_err(null, '参数错误:cardType或merchantNo');
        }
        if($param['acceptOrderId'] != $dbInfoData['acceptOrderId'] || $param['merchantOrderId'] != $dbInfoData['merchantOrderId']){
            return verify_err(null, '参数错误:acceptOrderId或merchantOrderId');
        }
        return auto_success(null, '所有参数正确');
    }

    /*支付成功，充值失败后的处理
    1、添加回调记录
    2、修改支付记录状态
    trueArr为查询订单后返回的res数组
    */
    private function _callRechargeFailure($trueArr, $findPayLogWhere, $erroMsg)
    {
        $payLogModel = $this->model('\app\serverfund\model\PayLog');
        $callBackLogic = logic('app\serverfund\logic\CallbackLog');

        $saveErroPayLog['return_param'] = $trueArr;
        $saveErroPayLog['return_status'] = 2;
        //$saveErroPayLog['return_result_code'] = $xmlArray['result_code'];
        $saveErroPayLog['status'] = 1;
        $saveErroPayLog['result_status'] = 2;
        $saveErroPayLogRes = $payLogModel->save($saveErroPayLog, $findPayLogWhere);
        //添加记录
        $addLog['xml'] = $trueArr;
        $addLog['remark'] = '支付成功，充值失败!错误原因：' . $erroMsg;
        $addLog['status'] = 2;
        $addCallbackLog = $callBackLogic->addLog($addLog);
    }

    /*将字符串格式转化为数据形式*/
    private function _stringToArray(string $context): array 
    {
        $res = [];
        $contextArray = explode("&", $context);
        foreach ($contextArray as $k => $v) {
            $vArray = explode("=", $v);
            $res[$vArray[0]] = $vArray[1];
        }
        return $res;
    }


}